import 'package:flutter/material.dart';
import 'point.dart';
import 'point_view.dart';
import 'line_view.dart';

class GestureView extends StatefulWidget {
  final double size;
  final Color selectColor;
  final Color unSelectColor;
  final double ringWidth;
  final double ringRadius;
  final double circleRadius;
  final double lineWidth;
  final bool showUnSelectRing;
  final bool immediatelyClear;
  late List<Point> points;
  void Function()? onPanDown;
  void Function(List<int>)? onPanUp;

  GestureView(
      {super.key,
      required this.size,
      this.selectColor = Colors.blue,
      this.unSelectColor = Colors.grey,
      this.ringWidth = 4,
      this.ringRadius = 30,
      this.showUnSelectRing = true,
      this.circleRadius = 20,
      this.lineWidth = 6,
      this.onPanUp,
      this.onPanDown,
      this.immediatelyClear = false}) {
    // 减少刷新频率
    points = [];
    final realRingSize = ringRadius + ringWidth / 2;
    final gapWidth = size / 6 - realRingSize;
    for (int i = 0; i < 9; i++) {
      double x = gapWidth + realRingSize;
      double y = gapWidth + realRingSize;
      points.add(Point(x: (1 + i % 3 * 2) * x, y: (1 + i ~/ 3 * 2) * y, position: i));
    }
  }

  @override
  State<GestureView> createState() => _GestureState(
      size: size,
      ringWidth: ringWidth,
      ringRadius: ringRadius,
      showUnSelectRing: showUnSelectRing,
      circleRadius: circleRadius,
      selectColor: selectColor,
      unSelectColor: unSelectColor,
      points: points,
      lineWidth: lineWidth,
      onPanDown: onPanDown,
      onPanUp: onPanUp,
      immediatelyClear: immediatelyClear);
}

class _GestureState extends State<GestureView> {
  final double size;
  final double ringWidth;
  final double ringRadius;
  final bool showUnSelectRing;
  final double circleRadius;
  Color selectColor; // open only
  final Color unSelectColor;
  final double lineWidth;
  final List<Point> points;
  final void Function()? onPanDown;
  final void Function(List<int>)? onPanUp;
  final List<Point> pathPoints = [];
  double realRadius = 0;
  late Point curPoint;
  final bool immediatelyClear;

  _GestureState({
    required this.size,
    required this.selectColor,
    required this.unSelectColor,
    required this.ringWidth,
    required this.ringRadius,
    required this.showUnSelectRing,
    required this.circleRadius,
    required this.points,
    required this.lineWidth,
    this.onPanDown,
    this.onPanUp,
    required this.immediatelyClear,
  });

  @override
  void initState() {
    realRadius = ringRadius + ringWidth / 2;
    curPoint = Point(x: 0, y: 0, position: 0);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        CustomPaint(
          size: Size(size, size),
          painter: PointView(
              ringWidth: ringWidth,
              ringRadius: ringRadius,
              showUnSelectRing: showUnSelectRing,
              circleRadius: circleRadius,
              selectColor: selectColor,
              unSelectColor: unSelectColor,
              points: points),
        ),
        GestureDetector(
            onPanDown: _onPanDown,
            onPanUpdate: (DragUpdateDetails e) => _onPanUpdate(e, context),
            onPanEnd: (DragEndDetails e) => _onPanEnd(e, context),
            child: CustomPaint(
              size: Size(size, size),
              painter: LineView(
                  pathPoints: pathPoints,
                  selectColor: selectColor,
                  lineWidth: lineWidth,
                  curPoint: curPoint),
            ))
      ],
    );
  }

  void _onPanDown(DragDownDetails e) {
    _clearAllData();
    final onPanDown = this.onPanDown;
    if (onPanDown != null) onPanDown.call();
  }

  void _onPanUpdate(DragUpdateDetails e, BuildContext context) {
    RenderBox box = context.findRenderObject() as RenderBox;
    Offset offset = box.globalToLocal(e.globalPosition);
    _slideDealt(offset);
    setState(() {
      curPoint = Point(x: offset.dx, y: offset.dy, position: -1);
    });
  }

  void _onPanEnd(DragEndDetails e, BuildContext context) {
    if (pathPoints.isNotEmpty) {
      setState(() {
        curPoint = pathPoints[pathPoints.length - 1];
      });
      if (onPanUp != null) {
        List<int> items = pathPoints.map((item) => item.position).toList();
        onPanUp!(items);
      }
      if (immediatelyClear) _clearAllData(); //clear data
    }
  }

  void _slideDealt(Offset offSet) {
    int xPosition = -1;
    int yPosition = -1;
    for (int i = 0; i < 3; i++) {
      if (xPosition == -1 &&
          points[i].x + realRadius >= offSet.dx &&
          offSet.dx >= points[i].x - realRadius) {
        xPosition = i;
      }
      if (yPosition == -1 &&
          points[i * 3].y + realRadius >= offSet.dy &&
          offSet.dy >= points[i * 3].y - realRadius) {
        yPosition = i;
      }
    }
    if (xPosition == -1 || yPosition == -1) return;
    int position = yPosition * 3 + xPosition;

    if (!points[position].isSelect) {
      points[position].isSelect = true;
      pathPoints.add(points[position]);
    }
  }

  void _clearAllData() {
    for (int i = 0; i < 9; i++) {
      points[i].isSelect = false;
    }
    pathPoints.clear();
    setState(() {});
  }
}
